﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

namespace Niaofei.WPF.Control
{
    public class BusyIndicator
    {
        private readonly FrameworkElement _targetElement;
        private Loading? _overlay;
        private AdornerLayer? _adornerLayer;
        private BusyAdorner? _adorner;

        public BusyIndicator(FrameworkElement targetElement)
        {
            _targetElement = targetElement;
        }

        public void Start(string? message)
        {
            if (_targetElement.Dispatcher.CheckAccess())
            {
                DoStart(message);
            }
            else
            {
                _targetElement.Dispatcher.Invoke(() => DoStart(message));
            }
        }

        private void DoStart(string? message)
        {
            if (_adorner != null)
            {
                return;
            }

            var d = Math.Min(_targetElement.ActualHeight, _targetElement.ActualWidth);
            d = d > 30 ? 30 : d;
            var height = message == null ? d : d + 20;

            _overlay = new Loading()
            {
                IsEnabled = true,
                Content = message,
                Width = _targetElement.ActualWidth,
                Height = height,
                Diameter = d,
            };

            _adorner = new BusyAdorner(_targetElement, _overlay);

            _adornerLayer = AdornerLayer.GetAdornerLayer(_targetElement);
            if (_adornerLayer == null)
            {
                var decorator = new AdornerDecorator();
                if (_targetElement.Parent is Panel parentPanel)
                {
                    var index = parentPanel.Children.IndexOf(_targetElement);
                    parentPanel.Children.Remove(_targetElement);
                    decorator.Child = _targetElement;
                    parentPanel.Children.Insert(index, decorator);
                    _adornerLayer = AdornerLayer.GetAdornerLayer(_targetElement);
                }
            }

            if (_adornerLayer != null)
            {
                _adornerLayer.Add(_adorner);
            }
        }

        public void Stop()
        {
            if (_targetElement.Dispatcher.CheckAccess())
            {
                DoStop();
            }
            else
            {
                _targetElement.Dispatcher.Invoke(DoStop);
            }
        }

        private void DoStop()
        {
            if (_adorner == null || _adornerLayer == null || _overlay == null)
            {
                return;
            }

            _overlay.IsEnabled = false;
            _adornerLayer.Remove(_adorner);
            _adorner.DisconnectChild();
            _adorner = null;
            _adornerLayer = null;
            _overlay = null;
        }
    }


    internal class BusyAdorner : Adorner
    {
        private readonly Loading _child;

        public BusyAdorner(UIElement adornedElement, Loading child)
            : base(adornedElement)
        {
            _child = child;
            AddVisualChild(child);
        }

        protected override int VisualChildrenCount => 1;

        protected override Visual GetVisualChild(int index) => _child;

        protected override Size ArrangeOverride(Size finalSize)
        {
            _child.Arrange(new Rect(finalSize));
            return finalSize;
        }

        public void DisconnectChild()
        {
            RemoveVisualChild(_child);
        }
    }
}
